#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
语音录入模块
Voice Recording Module

使用PyAudio和WebRTC VAD进行智能语音录制
Intelligent voice recording using PyAudio and WebRTC VAD
"""

import pyaudio
import wave
import threading
import time
import os
import logging
import sys
from typing import Optional, Dict, Any, Callable
from queue import Queue
from pathlib import Path

# 添加路径以导入串口通信模块
sys.path.append(str(Path(__file__).parent.parent))
from utils.serial_comm import SerialCommunicator

# 条件导入webrtcvad
try:
    import webrtcvad
    WEBRTCVAD_AVAILABLE = True
except ImportError:
    WEBRTCVAD_AVAILABLE = False
    print("Warning: webrtcvad not available. VAD functionality will be disabled.")


def create_pyaudio_instance():
    """
    创建PyAudio实例，处理Linux环境下的兼容性问题
    Create PyAudio instance, handling Linux compatibility issues
    """
    import platform
    
    # 在Linux环境下设置环境变量以提高稳定性
    if platform.system() == 'Linux':
        import os
        # 设置ALSA环境变量
        os.environ.setdefault('ALSA_CARD', '0')
        os.environ.setdefault('ALSA_DEVICE', '0')
        # 禁用ALSA调试输出
        os.environ.setdefault('ALSA_DEBUG', '0')
        os.environ.setdefault('ALSA_QUIET', '1')
    
    try:
        # 创建PyAudio实例
        p = pyaudio.PyAudio()
        
        # 检查是否有输入设备
        device_count = p.get_device_count()
        has_input_device = False
        
        for i in range(device_count):
            try:
                device_info = p.get_device_info_by_index(i)
                if device_info.get('maxInputChannels', 0) > 0:
                    has_input_device = True
                    break
            except Exception:
                continue
        
        if not has_input_device:
            try:
                p.terminate()
            except Exception:
                pass
            raise Exception("No input audio devices found")
        
        return p
        
    except Exception as e:
        raise Exception(f"Failed to initialize PyAudio: {e}")


class VoiceRecorder:
    """
    语音录制器类
    Voice recorder class
    
    支持VAD语音活动检测的智能录音功能
    Intelligent recording with VAD (Voice Activity Detection)
    """
    
    def __init__(self, config: Dict[str, Any]):
        """
        初始化语音录制器
        Initialize voice recorder
        
        Args:
            config (Dict[str, Any]): 配置参数 / Configuration parameters
                - sample_rate: 采样率 / Sample rate (default: 16000)
                - frame_duration_ms: 帧时长(ms) / Frame duration in ms (default: 30)
                - vad_mode: VAD模式 0-3 / VAD mode 0-3 (default: 2)
                - mic_index: 麦克风索引 / Microphone index (default: None)
                - output_dir: 输出目录 / Output directory (default: './audio/recorded')
                - max_silence_frames: 最大静音帧数 / Max silence frames (default: 60)
                - min_speech_frames: 最小语音帧数 / Min speech frames (default: 10)
        """
        self.config = config
        self.sample_rate = config.get('sample_rate', 16000)  # 默认采样率16000Hz，与VAD兼容
        self.frame_duration_ms = config.get('frame_duration_ms', 30)
        self.vad_mode = config.get('vad_mode', 2)
        self.mic_index = config.get('mic_index', None)
        self.output_dir = config.get('output_dir', './audio/recorded')
        self.max_silence_frames = config.get('max_silence_frames', 60)
        self.min_speech_frames = config.get('min_speech_frames', 10)
        
        # 硬件唤醒检测控制配置
        self.disable_wake_during_recording = config.get('disable_wake_during_recording', True)
        self.speech_serial_port = config.get('speech_serial_port', '/dev/myspeech')
        self.speech_baudrate = config.get('speech_baudrate', 115200)
        
        # 设置日志（必须在使用logger之前初始化）
        self.logger = logging.getLogger(__name__)
        
        # 计算帧参数
        self.frame_bytes = int(self.sample_rate * self.frame_duration_ms / 1000)
        
        # 实际使用的参数（可能因设备兼容性而调整）
        self.actual_sample_rate = self.sample_rate
        self.actual_frame_bytes = self.frame_bytes
        
        # 初始化VAD
        if WEBRTCVAD_AVAILABLE:
            # 检查VAD参数兼容性
            supported_rates = [8000, 16000, 32000, 48000]
            supported_frame_durations = [10, 20, 30]  # ms
            
            if (self.sample_rate in supported_rates and 
                self.frame_duration_ms in supported_frame_durations):
                try:
                    # Linux环境下的额外检查
                    import platform
                    if platform.system() == 'Linux':
                        # 在Linux下进行测试初始化，避免段错误
                        test_vad = webrtcvad.Vad(self.vad_mode)
                        # 测试一个小的音频帧
                        test_frame = b'\x00' * (self.frame_bytes * 2)  # 16-bit silence
                        try:
                            test_vad.is_speech(test_frame, self.sample_rate)
                            self.vad = test_vad
                            self.logger.info(f"VAD initialized and tested on Linux with sample_rate={self.sample_rate}, frame_duration={self.frame_duration_ms}ms")
                        except Exception as e:
                            self.logger.warning(f"VAD test failed on Linux, disabling VAD: {e}")
                            self.vad = None
                    else:
                        self.vad = webrtcvad.Vad(self.vad_mode)
                        self.logger.info(f"VAD initialized with sample_rate={self.sample_rate}, frame_duration={self.frame_duration_ms}ms")
                except Exception as e:
                    self.logger.warning(f"Failed to initialize VAD: {e}")
                    self.vad = None
            else:
                self.logger.warning(f"VAD not compatible with sample_rate={self.sample_rate}Hz, frame_duration={self.frame_duration_ms}ms")
                self.logger.info(f"Supported rates: {supported_rates}, Supported durations: {supported_frame_durations}ms")
                self.vad = None
        else:
            self.vad = None
            
        if self.vad is None:
            self.logger.info("Using simple recording mode without VAD")
        
        # 状态管理
        self.is_recording = False
        self.stop_event = threading.Event()
        self.recording_thread: Optional[threading.Thread] = None
        self.last_recording_path: Optional[str] = None  # 保存最后录音文件路径
        
        # 回调函数
        self.start_callback: Optional[Callable] = None
        self.stop_callback: Optional[Callable] = None
        self.speech_detected_callback: Optional[Callable] = None
        
        # 统计信息
        self.recording_count = 0
        self.total_recording_time = 0.0
        
        # 初始化硬件唤醒控制串口通信器
        self.speech_comm = None
        if self.disable_wake_during_recording:
            try:
                self.speech_comm = SerialCommunicator(
                    port=self.speech_serial_port,
                    baudrate=self.speech_baudrate,
                    timeout=1.0
                )
                self.logger.info(f"Speech serial communicator initialized for port {self.speech_serial_port}")
            except Exception as e:
                self.logger.warning(f"Failed to initialize speech serial communicator: {e}")
                self.speech_comm = None
        
        # 确保输出目录存在
        os.makedirs(self.output_dir, exist_ok=True)
        
    def set_callbacks(self, 
                     start_callback: Optional[Callable] = None,
                     stop_callback: Optional[Callable] = None,
                     speech_detected_callback: Optional[Callable] = None):
        """
        设置回调函数
        Set callback functions
        
        Args:
            start_callback: 开始录音回调 / Start recording callback
            stop_callback: 停止录音回调 / Stop recording callback  
            speech_detected_callback: 检测到语音回调 / Speech detected callback
        """
        self.start_callback = start_callback
        self.stop_callback = stop_callback
        self.speech_detected_callback = speech_detected_callback
        
    def _disable_hardware_wake_detection(self) -> bool:
        """
        关闭硬件唤醒检测
        Disable hardware wake detection
        
        Returns:
            bool: 是否成功关闭 / Whether successfully disabled
        """
        if not self.speech_comm:
            return True  # 如果没有串口通信器，认为成功
            
        try:
            if not self.speech_comm.is_connected():
                if not self.speech_comm.open():
                    self.logger.warning("Failed to open speech serial connection")
                    return False
                    
            # 发送关闭唤醒检测命令 (根据硬件协议定义)
            # 这里使用通用的关闭命令，具体命令需要根据硬件文档调整
            disable_cmd = "WAKE_DISABLE\n"  # 示例命令
            if self.speech_comm.send_data(disable_cmd):
                self.logger.info("Hardware wake detection disabled")
                return True
            else:
                self.logger.warning("Failed to send disable wake detection command")
                return False
                
        except Exception as e:
            self.logger.error(f"Error disabling hardware wake detection: {e}")
            return False
            
    def _enable_hardware_wake_detection(self) -> bool:
        """
        启用硬件唤醒检测
        Enable hardware wake detection
        
        Returns:
            bool: 是否成功启用 / Whether successfully enabled
        """
        if not self.speech_comm:
            return True  # 如果没有串口通信器，认为成功
            
        try:
            if not self.speech_comm.is_connected():
                if not self.speech_comm.open():
                    self.logger.warning("Failed to open speech serial connection")
                    return False
                    
            # 发送启用唤醒检测命令 (根据硬件协议定义)
            # 这里使用通用的启用命令，具体命令需要根据硬件文档调整
            enable_cmd = "WAKE_ENABLE\n"  # 示例命令
            if self.speech_comm.send_data(enable_cmd):
                self.logger.info("Hardware wake detection re-enabled")
                return True
            else:
                self.logger.warning("Failed to send enable wake detection command")
                return False
                
        except Exception as e:
            self.logger.error(f"Error enabling hardware wake detection: {e}")
            return False
        
    def record_audio(self, output_filename: Optional[str] = None, 
                    timeout: Optional[float] = None) -> Optional[str]:
        """
        录制音频（阻塞方式）
        Record audio (blocking)
        
        Args:
            output_filename: 输出文件名 / Output filename
            timeout: 录音超时时间 / Recording timeout
            
        Returns:
            str: 录音文件路径，失败返回None / Recording file path, None if failed
        """
        if self.is_recording:
            self.logger.warning("Recording is already in progress")
            return None
            
        # 生成输出文件名
        if output_filename is None:
            timestamp = int(time.time())
            output_filename = f"recording_{timestamp}.wav"
            
        output_path = os.path.join(self.output_dir, output_filename)
        
        # 开始录音
        return self._record_with_vad(output_path, timeout)
        
    def record_audio_with_retry(self, output_filename: Optional[str] = None, 
                               timeout: Optional[float] = None, 
                               max_retries: int = 5) -> Optional[str]:
        """
        循环录制音频，直到获得有效录音（阻塞方式）
        Record audio with retry until valid recording is obtained (blocking)
        
        Args:
            output_filename: 输出文件名 / Output filename
            timeout: 单次录音超时时间 / Single recording timeout
            max_retries: 最大重试次数 / Maximum retry attempts
            
        Returns:
            str: 录音文件路径，失败返回None / Recording file path, None if failed
        """
        retry_count = 0
        
        while retry_count < max_retries:
            self.logger.info(f"录音尝试 {retry_count + 1}/{max_retries} / Recording attempt {retry_count + 1}/{max_retries}")
            
            # 生成带重试次数的文件名
            if output_filename is None:
                timestamp = int(time.time())
                filename = f"recording_{timestamp}_{retry_count + 1}.wav"
            else:
                name, ext = os.path.splitext(output_filename)
                filename = f"{name}_{retry_count + 1}{ext}"
                
            result = self.record_audio(filename, timeout)
            
            if result is not None:
                self.logger.info(f"录音成功！/ Recording successful! File: {result}")
                return result
            else:
                retry_count += 1
                if retry_count < max_retries:
                    self.logger.info("录音失败，准备重试... / Recording failed, preparing to retry...")
                    time.sleep(0.5)  # 短暂等待后重试
                    
        self.logger.warning(f"录音失败，已达到最大重试次数 {max_retries} / Recording failed after {max_retries} attempts")
        return None
        
    def start_continuous_segment_recording(self, base_filename: Optional[str] = None, 
                                         min_segment_frames: int = None) -> None:
        """
        开始连续分段录音，持续监听并自动保存每段语音
        Start continuous segment recording, continuously listen and auto-save each speech segment
        
        Args:
            base_filename: 基础文件名，会自动添加序号 / Base filename, sequence number will be added
            min_segment_frames: 最小分段帧数，小于此值的录音会被丢弃 / Min segment frames, recordings below this will be discarded
        """
        if self.is_recording:
            self.logger.warning("Recording is already in progress")
            return
            
        if min_segment_frames is None:
            min_segment_frames = self.min_speech_frames
            
        # 生成基础文件名
        if base_filename is None:
            timestamp = int(time.time())
            base_filename = f"segment_{timestamp}"
            
        # 启动连续分段录音线程
        self.stop_event.clear()
        self.recording_thread = threading.Thread(
            target=self._continuous_segment_recording,
            args=(base_filename, min_segment_frames),
            daemon=True
        )
        self.recording_thread.start()
        self.logger.info("连续分段录音已启动 / Continuous segment recording started")
        
    def start_single_segment_recording(self, base_filename: Optional[str] = None, 
                                     min_segment_frames: int = None) -> None:
        """
        开始单段录音，录制完第一段语音后立即停止
        Start single segment recording, stop immediately after recording the first speech segment
        
        Args:
            base_filename: 基础文件名，会自动添加序号 / Base filename, sequence number will be added
            min_segment_frames: 最小分段帧数，小于此值的录音会被丢弃 / Min segment frames, recordings below this will be discarded
        """
        if self.is_recording:
            self.logger.warning("Recording is already in progress")
            return
            
        if min_segment_frames is None:
            min_segment_frames = self.min_speech_frames
            
        # 生成基础文件名
        if base_filename is None:
            timestamp = int(time.time())
            base_filename = f"single_segment_{timestamp}"
            
        # 启动单段录音线程
        self.stop_event.clear()
        self.recording_thread = threading.Thread(
            target=self._single_segment_recording,
            args=(base_filename, min_segment_frames),
            daemon=True
        )
        self.recording_thread.start()
        self.logger.info("单段录音已启动 / Single segment recording started")
        
    def start_continuous_recording(self, output_filename: Optional[str] = None, duration: Optional[float] = None, use_vad: Optional[bool] = None):
        """
        开始连续录音（非阻塞）
        Start continuous recording (non-blocking)
        
        Args:
            output_filename: 输出文件名 / Output filename
            duration: 录音时长（秒），None表示无限时长 / Recording duration (seconds), None for unlimited
            use_vad: 是否使用VAD检测，None表示根据duration自动判断 / Whether to use VAD detection, None for auto decision based on duration
        """
        if self.is_recording:
            self.logger.warning("Recording is already in progress")
            return
            
        # 生成输出文件名
        if output_filename is None:
            timestamp = int(time.time())
            output_filename = f"recording_{timestamp}.wav"
            
        output_path = os.path.join(self.output_dir, output_filename)
        self.last_recording_path = output_path  # 保存录音文件路径
        
        # 启动录音线程
        self.stop_event.clear()
        self.recording_thread = threading.Thread(
            target=self._record_with_vad,
            args=(output_path, duration, use_vad),
            daemon=True
        )
        self.recording_thread.start()
        
    def stop_recording(self) -> Optional[str]:
        """
        停止录音
        Stop recording
        
        Returns:
            Optional[str]: 录音文件路径 / Recording file path
        """
        if not self.is_recording:
            return self.last_recording_path
            
        self.stop_event.set()
        if self.recording_thread and self.recording_thread.is_alive():
            self.recording_thread.join(timeout=5.0)
            
        return self.last_recording_path
            
    def _record_with_vad(self, output_path: str, timeout: Optional[float], use_vad: Optional[bool] = None) -> Optional[str]:
        """
        使用VAD进行智能录音
        Intelligent recording with VAD
        
        Args:
            output_path: 输出文件路径 / Output file path
            timeout: 超时时间 / Timeout
            use_vad: 是否使用VAD检测，None表示根据timeout自动判断 / Whether to use VAD detection, None for auto decision based on timeout
            
        Returns:
            str: 录音文件路径，失败返回None / Recording file path, None if failed
        """
        self.is_recording = True
        start_time = time.time()
        
        # 关闭硬件唤醒检测以避免冲突
        wake_detection_disabled = False
        if self.disable_wake_during_recording:
            wake_detection_disabled = self._disable_hardware_wake_detection()
            if wake_detection_disabled:
                self.logger.info("Hardware wake detection disabled for recording")
            else:
                self.logger.warning("Failed to disable hardware wake detection, may cause conflicts")
        
        # 调用开始回调
        if self.start_callback:
            try:
                self.logger.debug("Calling start callback...")
                self.start_callback()
                self.logger.debug("Start callback completed successfully")
            except Exception as e:
                self.logger.error(f"Error in start callback: {e}")
                
        self.logger.debug("About to create PyAudio instance...")
                
        # 初始化PyAudio
        try:
            p = create_pyaudio_instance()
        except Exception as e:
            self.logger.error(f"Failed to initialize PyAudio: {e}")
            self.is_recording = False
            if self.stop_callback:
                try:
                    self.stop_callback()
                except Exception as callback_e:
                    self.logger.error(f"Error in stop callback: {callback_e}")
            return None
        audio_buffer = []
        silence_counter = 0
        speaking = False
        frame_counter = 0
        speech_frame_count = 0
        
        # 配置音频流参数
        self.logger.debug(f"Configuring audio stream parameters: rate={self.sample_rate}, channels=1, format=paInt16")
        stream_kwargs = {
            "format": pyaudio.paInt16,
            "channels": 1,
            "rate": self.sample_rate,
            "input": True,
            "frames_per_buffer": self.frame_bytes,
        }
        
        if self.mic_index is not None:
            self.logger.debug(f"Using specific microphone index: {self.mic_index}")
            stream_kwargs["input_device_index"] = self.mic_index
        else:
            self.logger.debug("Using default microphone device")
            
        stream = None
        try:
            # 尝试打开音频流，如果失败则尝试使用默认设备和不同采样率
            # 使用VAD兼容的采样率：8000, 16000, 32000, 48000 Hz
            fallback_rates = [self.sample_rate, 48000, 32000, 16000, 8000]
            stream_opened = False
            
            for rate in fallback_rates:
                stream_kwargs["rate"] = rate
                # 重新计算帧大小
                frame_bytes = int(rate * self.frame_duration_ms / 1000)
                stream_kwargs["frames_per_buffer"] = frame_bytes
                
                try:
                    stream = p.open(**stream_kwargs)
                    if rate != self.sample_rate:
                        self.logger.info(f"Using fallback sample rate: {rate}Hz (original: {self.sample_rate}Hz)")
                        # 更新实际使用的采样率
                        self.actual_sample_rate = rate
                        self.actual_frame_bytes = frame_bytes
                    else:
                        self.actual_sample_rate = self.sample_rate
                        self.actual_frame_bytes = self.frame_bytes
                    stream_opened = True
                    break
                except Exception as e:
                    self.logger.debug(f"Failed to open stream with rate {rate}Hz: {e}")
                    continue
            
            if not stream_opened:
                # 如果指定设备失败，尝试默认设备
                if "input_device_index" in stream_kwargs:
                    self.logger.warning("Failed to open specified device, trying default device")
                    del stream_kwargs["input_device_index"]
                    
                    # 使用相同的VAD兼容采样率列表
                    for rate in [self.sample_rate, 48000, 32000, 16000, 8000]:
                        stream_kwargs["rate"] = rate
                        frame_bytes = int(rate * self.frame_duration_ms / 1000)
                        stream_kwargs["frames_per_buffer"] = frame_bytes
                        
                        try:
                            stream = p.open(**stream_kwargs)
                            self.logger.info(f"Using default device with sample rate: {rate}Hz")
                            self.actual_sample_rate = rate
                            self.actual_frame_bytes = frame_bytes
                            stream_opened = True
                            break
                        except Exception as e:
                            self.logger.debug(f"Failed to open default device with rate {rate}Hz: {e}")
                            continue
            
            if not stream_opened:
                p.terminate()
                self.is_recording = False
                if self.stop_callback:
                    try:
                        self.stop_callback(False, None)
                    except Exception as callback_e:
                        self.logger.error(f"Error in stop callback: {callback_e}")
                raise Exception("Failed to open audio stream with any supported sample rate")
            
            self.logger.info(f"Started recording to {output_path}")
            
            while True:
                # 检查停止事件
                if self.stop_event.is_set():
                    self.logger.info("Recording stopped by stop event")
                    break
                    
                # 检查超时
                current_time = time.time()
                elapsed_time = current_time - start_time
                if timeout and elapsed_time > timeout:
                    self.logger.info(f"Recording stopped due to timeout ({timeout}s), actual elapsed: {elapsed_time:.2f}s")
                    # 为了确保达到完整的录制时长，多录制几帧
                    for _ in range(10):  # 多录制10帧作为补偿
                        try:
                            frame = stream.read(self.actual_frame_bytes, exception_on_overflow=False)
                            audio_buffer.append(frame)
                        except Exception:
                            break
                    break
                    
                # 读取音频帧
                try:
                    frame = stream.read(self.actual_frame_bytes, exception_on_overflow=False)
                except Exception as e:
                    self.logger.error(f"Error reading audio frame: {e}")
                    break
                    
                # 决定是否使用VAD
                should_use_vad = False
                if use_vad is not None:
                    # 明确指定是否使用VAD
                    should_use_vad = use_vad and self.vad is not None
                else:
                    # 自动判断：有timeout时不使用VAD，无timeout时使用VAD
                    should_use_vad = timeout is None and self.vad is not None
                
                # VAD检测或简单录音模式
                if should_use_vad:
                    # 使用VAD检测
                    try:
                        # 验证音频帧长度和格式
                        if len(frame) != self.actual_frame_bytes * 2:  # 16-bit = 2 bytes per sample
                            self.logger.warning(f"Frame size mismatch: expected {self.actual_frame_bytes * 2}, got {len(frame)}")
                            is_speech = False
                        else:
                            is_speech = self.vad.is_speech(frame, self.actual_sample_rate)
                    except Exception as e:
                        self.logger.warning(f"VAD processing error: {e}, disabling VAD for this session")
                        self.vad = None  # 禁用VAD避免后续错误
                        is_speech = False
                    
                    if is_speech:
                        # 检测到语音活动
                        if not speaking:
                            speaking = True
                            if self.speech_detected_callback:
                                try:
                                    self.speech_detected_callback()
                                except Exception as e:
                                    self.logger.error(f"Error in speech detected callback: {e}")
                                    
                        audio_buffer.append(frame)
                        silence_counter = 0
                        speech_frame_count += 1
                    else:
                        if speaking:
                            # 在语音活动后检测静音
                            silence_counter += 1
                            audio_buffer.append(frame)
                            
                            # 静音持续时间达标时结束录音
                            if silence_counter >= self.max_silence_frames:
                                self.logger.info(f"Recording ended due to silence (frames: {len(audio_buffer)})")
                                break
                        else:
                            # 还未开始说话，继续等待
                            pass
                else:
                    # 简单录音模式（无VAD）
                    audio_buffer.append(frame)
                    if not speaking:
                        speaking = True
                        if self.speech_detected_callback:
                            try:
                                self.speech_detected_callback()
                            except Exception as e:
                                self.logger.error(f"Error in speech detected callback: {e}")
                    speech_frame_count += 1
                    is_speech = True  # 假设所有帧都是语音
                        
                frame_counter += 1
                
                # 可选：实时状态显示
                if frame_counter % 10 == 0:
                    status = "🎤" if is_speech else "⏸️"
                    self.logger.debug(f"Recording status: {status} (frame: {frame_counter})")
                    
        except Exception as e:
            self.logger.error(f"Error during recording: {e}")
            return None
        finally:
            if stream is not None:
                try:
                    stream.stop_stream()
                    stream.close()
                except Exception as e:
                    self.logger.warning(f"Error closing stream: {e}")
            p.terminate()
            self.is_recording = False
            
        # 保存录音文件
        # 对于固定时长录音模式，绕过语音检测检查
        if timeout is not None:
            # 固定时长模式，强制保存录音
            success = self._save_audio_buffer_forced(audio_buffer, output_path, p)
        else:
            # VAD模式，使用正常的语音检测检查
            success = self._save_audio_buffer(audio_buffer, output_path, p, speaking, speech_frame_count)
        
        # 调用停止回调
        if self.stop_callback:
            try:
                self.stop_callback(success, output_path if success else None)
            except Exception as e:
                self.logger.error(f"Error in stop callback: {e}")
                
        # 重新启用硬件唤醒检测
        if self.disable_wake_during_recording and wake_detection_disabled:
            if self._enable_hardware_wake_detection():
                self.logger.info("Hardware wake detection re-enabled after recording completed")
            else:
                self.logger.warning("Failed to re-enable hardware wake detection after recording")
                
        # 更新统计信息
        if success:
            self.recording_count += 1
            self.total_recording_time += time.time() - start_time
            
        return output_path if success else None
        
    def _continuous_segment_recording(self, base_filename: str, min_segment_frames: int):
        """
        连续分段录音的内部实现
        Internal implementation of continuous segment recording
        
        Args:
            base_filename: 基础文件名 / Base filename
            min_segment_frames: 最小分段帧数 / Min segment frames
        """
        self.is_recording = True
        segment_count = 0
        
        # 关闭硬件唤醒检测以避免冲突
        wake_detection_disabled = False
        if self.disable_wake_during_recording:
            wake_detection_disabled = self._disable_hardware_wake_detection()
            if wake_detection_disabled:
                self.logger.info("Hardware wake detection disabled for segment recording")
            else:
                self.logger.warning("Failed to disable hardware wake detection, may cause conflicts")
        
        # 调用开始回调
        if self.start_callback:
            try:
                self.start_callback()
            except Exception as e:
                self.logger.error(f"Error in start callback: {e}")
                
        # 初始化PyAudio
        p = None
        try:
            p = create_pyaudio_instance()
        except Exception as e:
            self.logger.error(f"Failed to initialize PyAudio: {e}")
            # 确保录制状态正确设置
            self.is_recording = False
            # 重新启用硬件唤醒检测
            if self.disable_wake_during_recording and wake_detection_disabled:
                self._enable_hardware_wake_detection()
            return
        
        # 配置音频流参数
        stream_kwargs = {
            "format": pyaudio.paInt16,
            "channels": 1,
            "rate": self.sample_rate,
            "input": True,
            "frames_per_buffer": self.frame_bytes,
        }
        
        if self.mic_index is not None:
            stream_kwargs["input_device_index"] = self.mic_index
            
        stream = None
        try:
            # 打开音频流
            self.logger.debug("Starting audio stream opening process...")
            fallback_rates = [self.sample_rate, 48000, 32000, 16000, 8000]
            stream_opened = False
            
            for rate in fallback_rates:
                self.logger.debug(f"Attempting to open stream with sample rate: {rate}Hz")
                stream_kwargs["rate"] = rate
                frame_bytes = int(rate * self.frame_duration_ms / 1000)
                stream_kwargs["frames_per_buffer"] = frame_bytes
                
                try:
                    self.logger.debug(f"Opening PyAudio stream with parameters: {stream_kwargs}")
                    stream = p.open(**stream_kwargs)
                    self.logger.debug(f"Stream opened successfully with rate {rate}Hz")
                    if rate != self.sample_rate:
                        self.logger.info(f"Using fallback sample rate: {rate}Hz (original: {self.sample_rate}Hz)")
                    self.actual_sample_rate = rate
                    self.actual_frame_bytes = frame_bytes
                    stream_opened = True
                    break
                except Exception as e:
                    self.logger.debug(f"Failed to open stream with rate {rate}Hz: {e}")
                    continue
            
            if not stream_opened:
                if "input_device_index" in stream_kwargs:
                    self.logger.warning("Failed to open specified device, trying default device")
                    del stream_kwargs["input_device_index"]
                    
                    for rate in [self.sample_rate, 48000, 32000, 16000, 8000]:
                        stream_kwargs["rate"] = rate
                        frame_bytes = int(rate * self.frame_duration_ms / 1000)
                        stream_kwargs["frames_per_buffer"] = frame_bytes
                        
                        try:
                            stream = p.open(**stream_kwargs)
                            self.logger.info(f"Using default device with sample rate: {rate}Hz")
                            self.actual_sample_rate = rate
                            self.actual_frame_bytes = frame_bytes
                            stream_opened = True
                            break
                        except Exception as e:
                            self.logger.debug(f"Failed to open default device with rate {rate}Hz: {e}")
                            continue
            
            if not stream_opened:
                # 清理PyAudio实例
                try:
                    p.terminate()
                except Exception:
                    pass
                # 重新启用硬件唤醒检测
                if self.disable_wake_during_recording and wake_detection_disabled:
                    self._enable_hardware_wake_detection()
                # 确保录制状态正确设置
                self.is_recording = False
                self.logger.error("Failed to open audio stream with any supported sample rate")
                return
            
            self.logger.info("连续分段录音开始监听 / Continuous segment recording started listening")
            
            # 连续监听循环
            while not self.stop_event.is_set():
                audio_buffer = []
                silence_counter = 0
                speaking = False
                speech_frame_count = 0
                
                # 等待语音开始
                while not self.stop_event.is_set():
                    try:
                        frame = stream.read(self.actual_frame_bytes, exception_on_overflow=False)
                    except Exception as e:
                        self.logger.error(f"Error reading audio frame: {e}")
                        break
                        
                    if self.vad is not None:
                        try:
                            # 验证音频帧长度和格式
                            if len(frame) != self.actual_frame_bytes * 2:  # 16-bit = 2 bytes per sample
                                self.logger.warning(f"Frame size mismatch: expected {self.actual_frame_bytes * 2}, got {len(frame)}")
                                is_speech = False
                            else:
                                is_speech = self.vad.is_speech(frame, self.actual_sample_rate)
                        except Exception as e:
                            self.logger.warning(f"VAD processing error: {e}, disabling VAD for this session")
                            self.vad = None  # 禁用VAD避免后续错误
                            is_speech = False
                    else:
                        # 简单音量检测作为语音活动检测的替代
                        import audioop
                        volume = audioop.rms(frame, 2)
                        is_speech = volume > 500  # 可调整的阈值
                    
                    if is_speech:
                        speaking = True
                        audio_buffer.append(frame)
                        speech_frame_count += 1
                        if self.speech_detected_callback:
                            try:
                                self.speech_detected_callback()
                            except Exception as e:
                                self.logger.error(f"Error in speech detected callback: {e}")
                        break
                
                if self.stop_event.is_set():
                    break
                    
                # 继续录制直到静音
                while not self.stop_event.is_set() and speaking:
                    try:
                        frame = stream.read(self.actual_frame_bytes, exception_on_overflow=False)
                    except Exception as e:
                        self.logger.error(f"Error reading audio frame: {e}")
                        break
                        
                    if self.vad is not None:
                        try:
                            # 验证音频帧长度和格式
                            if len(frame) != self.actual_frame_bytes * 2:  # 16-bit = 2 bytes per sample
                                self.logger.warning(f"Frame size mismatch: expected {self.actual_frame_bytes * 2}, got {len(frame)}")
                                is_speech = False
                            else:
                                is_speech = self.vad.is_speech(frame, self.actual_sample_rate)
                        except Exception as e:
                            self.logger.warning(f"VAD processing error: {e}, disabling VAD for this session")
                            self.vad = None  # 禁用VAD避免后续错误
                            is_speech = False
                    else:
                        import audioop
                        volume = audioop.rms(frame, 2)
                        is_speech = volume > 500
                    
                    audio_buffer.append(frame)
                    
                    if is_speech:
                        silence_counter = 0
                        speech_frame_count += 1
                    else:
                        silence_counter += 1
                        if silence_counter >= self.max_silence_frames:
                            break
                
                # 保存当前分段
                if speaking and speech_frame_count >= min_segment_frames:
                    segment_count += 1
                    segment_filename = f"{base_filename}_{segment_count:03d}.wav"
                    output_path = os.path.join(self.output_dir, segment_filename)
                    
                    success = self._save_audio_buffer(audio_buffer, output_path, p, speaking, speech_frame_count)
                    if success:
                        self.logger.info(f"分段 {segment_count} 已保存 / Segment {segment_count} saved: {segment_filename}")
                        if self.stop_callback:
                            try:
                                self.stop_callback(success, output_path)
                            except Exception as e:
                                self.logger.error(f"Error in stop callback: {e}")
                    else:
                        self.logger.warning(f"分段 {segment_count} 保存失败 / Segment {segment_count} save failed")
                elif speaking:
                    self.logger.debug(f"分段太短，已丢弃 ({speech_frame_count} 帧) / Segment too short, discarded ({speech_frame_count} frames)")
                    
        except Exception as e:
            self.logger.error(f"连续分段录音错误 / Continuous segment recording error: {e}")
        finally:
            if stream is not None:
                try:
                    stream.stop_stream()
                    stream.close()
                except Exception as e:
                    self.logger.warning(f"Error closing stream: {e}")
            p.terminate()
            self.is_recording = False
            
            # 重新启用硬件唤醒检测
            if self.disable_wake_during_recording and wake_detection_disabled:
                if self._enable_hardware_wake_detection():
                    self.logger.info("Hardware wake detection re-enabled after segment recording completed")
                else:
                    self.logger.warning("Failed to re-enable hardware wake detection after recording")
                    
            self.logger.info(f"连续分段录音结束，共保存 {segment_count} 个分段 / Continuous segment recording ended, {segment_count} segments saved")
        
    def _single_segment_recording(self, base_filename: str, min_segment_frames: int):
        """
        单段录音的内部实现，录制完第一段语音后立即停止
        Internal implementation of single segment recording, stop immediately after recording the first speech segment
        
        Args:
            base_filename: 基础文件名 / Base filename
            min_segment_frames: 最小分段帧数 / Min segment frames
        """
        self.is_recording = True
        
        # 关闭硬件唤醒检测以避免冲突
        wake_detection_disabled = False
        if self.disable_wake_during_recording:
            wake_detection_disabled = self._disable_hardware_wake_detection()
            if wake_detection_disabled:
                self.logger.info("Hardware wake detection disabled for single segment recording")
            else:
                self.logger.warning("Failed to disable hardware wake detection, may cause conflicts")
        
        # 调用开始回调
        if self.start_callback:
            try:
                self.start_callback()
            except Exception as e:
                self.logger.error(f"Error in start callback: {e}")
                
        # 初始化PyAudio
        try:
            self.logger.debug("Creating PyAudio instance...")
            p = create_pyaudio_instance()
            self.logger.debug("PyAudio instance created successfully")
        except Exception as e:
            self.logger.error(f"Failed to initialize PyAudio: {e}")
            return
        
        # 配置音频流参数
        stream_kwargs = {
            "format": pyaudio.paInt16,
            "channels": 1,
            "rate": self.sample_rate,
            "input": True,
            "frames_per_buffer": self.frame_bytes,
        }
        
        if self.mic_index is not None:
            stream_kwargs["input_device_index"] = self.mic_index
            
        stream = None
        try:
            # 打开音频流
            fallback_rates = [self.sample_rate, 48000, 32000, 16000, 8000]
            stream_opened = False
            
            for rate in fallback_rates:
                stream_kwargs["rate"] = rate
                frame_bytes = int(rate * self.frame_duration_ms / 1000)
                stream_kwargs["frames_per_buffer"] = frame_bytes
                
                try:
                    stream = p.open(**stream_kwargs)
                    if rate != self.sample_rate:
                        self.logger.info(f"Using fallback sample rate: {rate}Hz (original: {self.sample_rate}Hz)")
                    self.actual_sample_rate = rate
                    self.actual_frame_bytes = frame_bytes
                    stream_opened = True
                    break
                except Exception as e:
                    self.logger.debug(f"Failed to open stream with rate {rate}Hz: {e}")
                    continue
            
            if not stream_opened:
                if "input_device_index" in stream_kwargs:
                    self.logger.warning("Failed to open specified device, trying default device")
                    del stream_kwargs["input_device_index"]
                    
                    for rate in [self.sample_rate, 48000, 32000, 16000, 8000]:
                        stream_kwargs["rate"] = rate
                        frame_bytes = int(rate * self.frame_duration_ms / 1000)
                        stream_kwargs["frames_per_buffer"] = frame_bytes
                        
                        try:
                            stream = p.open(**stream_kwargs)
                            self.logger.info(f"Using default device with sample rate: {rate}Hz")
                            self.actual_sample_rate = rate
                            self.actual_frame_bytes = frame_bytes
                            stream_opened = True
                            break
                        except Exception as e:
                            self.logger.debug(f"Failed to open default device with rate {rate}Hz: {e}")
                            continue
            
            if not stream_opened:
                # 清理PyAudio实例
                try:
                    p.terminate()
                except Exception:
                    pass
                # 重新启用硬件唤醒检测
                if self.disable_wake_during_recording and wake_detection_disabled:
                    self._enable_hardware_wake_detection()
                # 确保录制状态正确设置
                self.is_recording = False
                self.logger.error("Failed to open audio stream with any supported sample rate")
                return
            
            self.logger.info("单段录音开始监听 / Single segment recording started listening")
            
            # 单段录音逻辑
            self.logger.debug("Initializing audio recording variables...")
            self.logger.info(f"[DEBUG] min_segment_frames设置为: {min_segment_frames}")
            audio_buffer = []
            silence_counter = 0
            speaking = False
            speech_frame_count = 0
            
            self.logger.debug(f"Starting audio frame reading loop with frame_bytes={self.actual_frame_bytes}")
            frame_count = 0
            
            # 等待语音开始
            while not self.stop_event.is_set():
                try:
                    frame_count += 1
                    if frame_count == 1:
                        self.logger.debug("Reading first audio frame...")
                    elif frame_count % 100 == 0:
                        self.logger.debug(f"Read {frame_count} audio frames successfully")
                    
                    # 检查流是否仍然活跃
                    if not stream.is_active():
                        self.logger.error("Audio stream is no longer active")
                        break
                    
                    self.logger.debug(f"About to read frame {frame_count} with {self.actual_frame_bytes} bytes...")
                    frame = stream.read(self.actual_frame_bytes, exception_on_overflow=False)
                    
                    if frame_count == 1:
                        self.logger.debug(f"First frame read successfully, length: {len(frame)} bytes")
                except Exception as e:
                    self.logger.error(f"Error reading audio frame: {e}")
                    # 如果是严重错误，立即退出
                    if "segmentation" in str(e).lower() or "memory" in str(e).lower():
                        self.logger.error("Critical audio error detected, stopping recording")
                        break
                    # 其他错误尝试继续
                    continue
                    
                if self.vad is not None:
                    try:
                        # 验证音频帧长度和格式
                        if len(frame) != self.actual_frame_bytes * 2:  # 16-bit = 2 bytes per sample
                            self.logger.warning(f"Frame size mismatch: expected {self.actual_frame_bytes * 2}, got {len(frame)}")
                            is_speech = False
                        else:
                            is_speech = self.vad.is_speech(frame, self.actual_sample_rate)
                    except Exception as e:
                        self.logger.warning(f"VAD processing error: {e}, disabling VAD for this session")
                        self.vad = None  # 禁用VAD避免后续错误
                        is_speech = False
                else:
                    # 简单音量检测作为语音活动检测的替代
                    import audioop
                    volume = audioop.rms(frame, 2)
                    is_speech = volume > 500  # 可调整的阈值
                
                if is_speech:
                    speaking = True
                    audio_buffer.append(frame)
                    speech_frame_count += 1
                    self.logger.info(f"[DEBUG] 检测到语音开始，speech_frame_count: {speech_frame_count}")
                    if self.speech_detected_callback:
                        try:
                            self.speech_detected_callback()
                        except Exception as e:
                            self.logger.error(f"Error in speech detected callback: {e}")
                    break
            
            if self.stop_event.is_set():
                return
                
            # 继续录制直到静音
            while not self.stop_event.is_set() and speaking:
                try:
                    frame = stream.read(self.actual_frame_bytes, exception_on_overflow=False)
                except Exception as e:
                    self.logger.error(f"Error reading audio frame: {e}")
                    break
                    
                if self.vad is not None:
                    try:
                        # 验证音频帧长度和格式
                        if len(frame) != self.actual_frame_bytes * 2:  # 16-bit = 2 bytes per sample
                            self.logger.warning(f"Frame size mismatch: expected {self.actual_frame_bytes * 2}, got {len(frame)}")
                            is_speech = False
                        else:
                            is_speech = self.vad.is_speech(frame, self.actual_sample_rate)
                    except Exception as e:
                        self.logger.warning(f"VAD processing error: {e}, disabling VAD for this session")
                        self.vad = None  # 禁用VAD避免后续错误
                        is_speech = False
                else:
                    import audioop
                    volume = audioop.rms(frame, 2)
                    is_speech = volume > 500
                
                audio_buffer.append(frame)
                
                if is_speech:
                    silence_counter = 0
                    speech_frame_count += 1
                    if speech_frame_count % 50 == 0:  # 每50帧输出一次调试信息
                        self.logger.info(f"[DEBUG] 持续语音中，speech_frame_count: {speech_frame_count}")
                else:
                    silence_counter += 1
                    if silence_counter >= self.max_silence_frames:
                        self.logger.info(f"[DEBUG] 检测到静音结束，silence_counter: {silence_counter}, max_silence_frames: {self.max_silence_frames}")
                        break
            
            # 保存录音段
            self.logger.info(f"[DEBUG] 录音结束检查 - speaking: {speaking}, speech_frame_count: {speech_frame_count}, min_segment_frames: {min_segment_frames}")
            self.logger.info(f"[DEBUG] 保存条件判断: {speaking and speech_frame_count >= min_segment_frames}")
            if speaking and speech_frame_count >= min_segment_frames:
                segment_filename = f"{base_filename}_001.wav"
                output_path = os.path.join(self.output_dir, segment_filename)
                self.logger.info(f"[DEBUG] 准备保存文件到: {output_path}")
                
                success = self._save_audio_buffer(audio_buffer, output_path, p, speaking, speech_frame_count)
                if success:
                    self.logger.info(f"单段录音已保存 / Single segment saved: {segment_filename}")
                    self.last_recording_path = output_path  # 保存最后录音文件路径
                    if self.stop_callback:
                        try:
                            self.stop_callback(success, output_path)
                        except Exception as e:
                            self.logger.error(f"Error in stop callback: {e}")
                else:
                    self.logger.warning("单段录音保存失败 / Single segment save failed")
                    self.logger.info(f"[DEBUG] 保存失败详情 - audio_buffer长度: {len(audio_buffer)}, output_path: {output_path}")
                    self.last_recording_path = None
            elif speaking:
                self.logger.info(f"[DEBUG] 录音段太短，已丢弃 ({speech_frame_count} 帧，需要 {min_segment_frames} 帧) / Segment too short, discarded ({speech_frame_count} frames, need {min_segment_frames} frames)")
                self.last_recording_path = None
            else:
                self.logger.info("[DEBUG] 未检测到语音，单段录音结束 / No speech detected, single segment recording ended")
                self.last_recording_path = None
                
            # 单段录制完成后立即停止
            self.stop_event.set()
                    
        except Exception as e:
            self.logger.error(f"单段录音错误 / Single segment recording error: {e}")
        finally:
            # 确保资源正确清理
            if stream is not None:
                try:
                    if stream.is_active():
                        stream.stop_stream()
                    stream.close()
                except Exception as e:
                    self.logger.warning(f"Error closing stream: {e}")
            
            if p is not None:
                try:
                    p.terminate()
                except Exception as e:
                    self.logger.warning(f"Error terminating PyAudio: {e}")
            
            # 重新启用硬件唤醒检测
            if self.disable_wake_during_recording and wake_detection_disabled:
                if self._enable_hardware_wake_detection():
                    self.logger.info("Hardware wake detection re-enabled after single segment recording completed")
                else:
                    self.logger.warning("Failed to re-enable hardware wake detection after recording")
                    
            # 确保录制状态正确设置
            self.is_recording = False
            self.logger.info("单段录音结束 / Single segment recording ended")
        
    def _save_audio_buffer(self, audio_buffer, output_path: str, p, speaking: bool, speech_frame_count: int) -> bool:
        """
        保存音频缓冲区到文件（带语音检测检查）
        Save audio buffer to file (with speech detection check)
        
        Args:
            audio_buffer: 音频缓冲区 / Audio buffer
            output_path: 输出路径 / Output path
            p: PyAudio实例 / PyAudio instance
            speaking: 是否检测到语音 / Whether speech was detected
            speech_frame_count: 语音帧数 / Speech frame count
            
        Returns:
            bool: 是否保存成功 / Whether saved successfully
        """
        self.logger.info(f"[DEBUG] _save_audio_buffer调用 - speaking: {speaking}, audio_buffer长度: {len(audio_buffer)}, speech_frame_count: {speech_frame_count}, min_speech_frames: {self.min_speech_frames}")
        
        if not speaking or len(audio_buffer) == 0:
            self.logger.warning(f"[DEBUG] 保存失败：speaking={speaking}, audio_buffer长度={len(audio_buffer)}")
            return False
            
        if speech_frame_count < self.min_speech_frames:
            self.logger.warning(f"[DEBUG] 语音太短不保存：{speech_frame_count} < {self.min_speech_frames} 帧")
            return False
            
        try:
            self.logger.info(f"[DEBUG] 开始保存WAV文件到: {output_path}")
            # 保存WAV文件
            with wave.open(output_path, "wb") as wf:
                wf.setnchannels(1)
                wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
                wf.setframerate(self.actual_sample_rate)
                wf.writeframes(b"".join(audio_buffer))
                
            self.logger.info(f"[DEBUG] 文件保存成功: {output_path} ({len(audio_buffer)} 帧)")
            return True
            
        except Exception as e:
            self.logger.error(f"Error saving audio file: {e}")
            return False
            
    def _save_audio_buffer_forced(self, audio_buffer, output_path: str, p) -> bool:
        """
        强制保存音频缓冲区到文件（绕过语音检测检查）
        Force save audio buffer to file (bypass speech detection check)
        
        Args:
            audio_buffer: 音频缓冲区 / Audio buffer
            output_path: 输出路径 / Output path
            p: PyAudio实例 / PyAudio instance
            
        Returns:
            bool: 是否保存成功 / Whether saved successfully
        """
        if len(audio_buffer) == 0:
            self.logger.warning("Empty audio buffer, not saving")
            return False
            
        try:
            # 保存WAV文件
            with wave.open(output_path, "wb") as wf:
                wf.setnchannels(1)
                wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
                wf.setframerate(self.actual_sample_rate)
                wf.writeframes(b"".join(audio_buffer))
                
            self.logger.info(f"Audio saved to {output_path} ({len(audio_buffer)} frames)")
            return True
            
        except Exception as e:
            self.logger.error(f"Error saving audio file: {e}")
            return False
            
    def get_available_devices(self) -> Dict[int, str]:
        """
        获取可用的音频输入设备
        Get available audio input devices
        
        Returns:
            Dict[int, str]: 设备索引和名称的映射 / Mapping of device index to name
        """
        # 初始化PyAudio
        try:
            p = create_pyaudio_instance()
        except Exception as e:
            return {}
        
        devices = {}
        
        try:
            for i in range(p.get_device_count()):
                device_info = p.get_device_info_by_index(i)
                if device_info['maxInputChannels'] > 0:
                    devices[i] = device_info['name']
        finally:
            p.terminate()
            
        return devices
        
    def get_status(self) -> Dict[str, Any]:
        """
        获取录制器状态信息
        Get recorder status information
        
        Returns:
            Dict[str, Any]: 状态信息 / Status information
        """
        return {
            'is_recording': self.is_recording,
            'sample_rate': self.sample_rate,
            'vad_mode': self.vad_mode,
            'mic_index': self.mic_index,
            'output_dir': self.output_dir,
            'recording_count': self.recording_count,
            'total_recording_time': self.total_recording_time,
            'available_devices': self.get_available_devices()
        }
        
    def __enter__(self):
        """上下文管理器入口 / Context manager entry"""
        return self
        
    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口 / Context manager exit"""
        if self.is_recording:
            self.stop_recording()